﻿#include "MirScene.h"
#include "../Settings.h"
#include "../Forms/Client.CMain.h"
#include "../MirGraphics/DXManager.h"
#include "../../Shared/Enums.h"
#include "../MirNetwork/Network.h"
#include "../MirScenes/GameScene.h"
#include "MirMessageBox.h"
#include "../../Shared/Language.h"

using namespace Client::MirGraphics;
using namespace Client::MirNetwork;
using namespace Client::MirScenes;
using namespace SlimDX::Direct3D9;
namespace S = ServerPackets;
namespace C = ClientPackets;

namespace Client::MirControls
{

MirScene *MirScene::ActiveScene = new LoginScene();
MouseButtons *MirScene::_buttons;
long long MirScene::_lastClickTime = 0;
MirControl *MirScene::_clickedControl;

    MirScene::MirScene()
    {
        setDrawControlTexture(true);
        setBackColour(Color::Magenta);
        Size tempVar(Settings::ScreenWidth, Settings::ScreenHeight);
        setSize(&tempVar);
    }

    Size *MirScene::getSize() const
    {
        return MirControl::getSize();
    }

    void MirScene::setSize(Size *value)
    {
        MirControl::setSize(value);
    }

    void MirScene::Draw()
    {
        if (isDisposed() || !getVisible())
        {
            return;
        }

        OnBeforeShown();

        DrawControl();

        if (CMain::DebugBaseLabel != nullptr && !CMain::DebugBaseLabel->isDisposed())
        {
            CMain::DebugBaseLabel->Draw();
        }

        if (CMain::HintBaseLabel != nullptr && !CMain::HintBaseLabel->isDisposed())
        {
            CMain::HintBaseLabel->Draw();
        }

        OnShown();
    }

    void MirScene::CreateTexture()
    {
        if (ControlTexture != nullptr && !ControlTexture->Disposed && getSize() != TextureSize)
        {
            ControlTexture->Dispose();
        }

        if (ControlTexture == nullptr || ControlTexture->Disposed)
        {
            DXManager::ControlList.push_back(this);
            ControlTexture = new Texture(DXManager::Device, getSize()->Width, getSize()->Height, 1, Usage::RenderTarget, Format::A8R8G8B8, Pool::Default);
            TextureSize = getSize();
        }
        Surface *oldSurface = DXManager::CurrentSurface;
        Surface *surface = ControlTexture->GetSurfaceLevel(0);
        DXManager::SetSurface(surface);

        DXManager::Device->Clear(ClearFlags::Target, getBackColour(), 0, 0);

        BeforeDrawControl();
        DrawChildControls();
        AfterDrawControl();

        DXManager::Sprite->Flush();


        DXManager::SetSurface(oldSurface);
        TextureValid = true;
        surface->Dispose();
    }

    void MirScene::OnMouseDown(MouseEventArgs *e)
    {
        if (!getEnabled())
        {
            return;
        }

        if (MouseControl != nullptr && MouseControl != this)
        {
            MouseControl->OnMouseDown(e);
        }
        else
        {
            MirControl::OnMouseDown(e);
        }
    }

    void MirScene::OnMouseUp(MouseEventArgs *e)
    {
        if (!getEnabled())
        {
            return;
        }
        if (MouseControl != nullptr && MouseControl != this)
        {
            MouseControl->OnMouseUp(e);
        }
        else
        {
            MirControl::OnMouseUp(e);
        }
    }

    void MirScene::OnMouseMove(MouseEventArgs *e)
    {
        if (!getEnabled())
        {
            return;
        }

        if (MouseControl != nullptr && MouseControl != this && MouseControl->Moving)
        {
            MouseControl->OnMouseMove(e);
        }
        else
        {
            MirControl::OnMouseMove(e);
        }
    }

    void MirScene::OnMouseWheel(MouseEventArgs *e)
    {
        if (!getEnabled())
        {
            return;
        }

        if (MouseControl != nullptr && MouseControl != this)
        {
            MouseControl->OnMouseWheel(e);
        }
        else
        {
            MirControl::OnMouseWheel(e);
        }
    }

    void MirScene::OnMouseClick(MouseEventArgs *e)
    {
        if (!getEnabled())
        {
            return;
        }
        if (_buttons == e->Button)
        {
            if (_lastClickTime + SystemInformation::DoubleClickTime >= CMain::Time)
            {
                OnMouseDoubleClick(e);
                return;
            }
        }
        else
        {
            _lastClickTime = 0;
        }

        if (ActiveControl != nullptr && ActiveControl->IsMouseOver(CMain::MPoint) && ActiveControl != this)
        {
            ActiveControl->OnMouseClick(e);
        }
        else
        {
            MirControl::OnMouseClick(e);
        }

        _clickedControl = ActiveControl;

        _lastClickTime = CMain::Time;
        _buttons = e->Button;
    }

    void MirScene::OnMouseDoubleClick(MouseEventArgs *e)
    {
        if (!getEnabled())
        {
            return;
        }
        _lastClickTime = 0;
        _buttons = MouseButtons::None;

        if (ActiveControl != nullptr && ActiveControl->IsMouseOver(CMain::MPoint) && ActiveControl != this)
        {
            if (ActiveControl == _clickedControl)
            {
                ActiveControl->OnMouseDoubleClick(e);
            }
            else
            {
                ActiveControl->OnMouseClick(e);
            }
        }
        else
        {
            if (ActiveControl == _clickedControl)
            {
                MirControl::OnMouseDoubleClick(e);
            }
            else
            {
                MirControl::OnMouseClick(e);
            }
        }
    }

    void MirScene::Redraw()
    {
        TextureValid = false;
    }

    void MirScene::ProcessPacket(Packet *p)
    {
        switch (p->getIndex())
        {
            case static_cast<short>(ServerPacketIds::Disconnect): // Disconnected
                Disconnect(static_cast<S::Disconnect*>(p));
                Network::Disconnect();
                break;
            case static_cast<short>(ServerPacketIds::NewItemInfo):
                NewItemInfo(static_cast<S::NewItemInfo*>(p));
                break;
            case static_cast<short>(ServerPacketIds::NewChatItem):
                NewChatItem(static_cast<S::NewChatItem*>(p));
                break;
            case static_cast<short>(ServerPacketIds::NewQuestInfo):
                NewQuestInfo(static_cast<S::NewQuestInfo*>(p));
                break;
            case static_cast<short>(ServerPacketIds::NewRecipeInfo):
                NewRecipeInfo(static_cast<S::NewRecipeInfo*>(p));
                break;
        }
    }

    void MirScene::NewItemInfo(S::NewItemInfo *info)
    {
        GameScene::ItemInfoList.push_back(info->Info);
    }

    void MirScene::NewChatItem(S::NewChatItem *p)
    {
        if (GameScene::ChatItemList.Any([&] (std::any x)
        {
            return x->UniqueID == p->Item->UniqueID;
        }))
        {
            return;
        }

        GameScene::Bind(p->Item);
        GameScene::ChatItemList.push_back(p->Item);
    }

    void MirScene::NewQuestInfo(S::NewQuestInfo *info)
    {
        GameScene::QuestInfoList.push_back(info->Info);
    }

    void MirScene::NewRecipeInfo(S::NewRecipeInfo *info)
    {
        GameScene::RecipeInfoList.push_back(info->Info);

        GameScene::Bind(info->Info->Item);

        for (int j = 0; j < info->Info->Tools.size(); j++)
        {
            GameScene::Bind(info->Info->Tools[j]);
        }

        for (int j = 0; j < info->Info->Ingredients.size(); j++)
        {
            GameScene::Bind(info->Info->Ingredients[j]);
        }
    }

    void MirScene::Disconnect(S::Disconnect *p)
    {
        switch (p->Reason)
        {
            case 0:
                MirMessageBox::Show(GameLanguage::ShuttingDown, true);
                break;
            case 1:
                MirMessageBox::Show("Disconnected: Another user logged onto your account.", true);
                break;
            case 2:
                MirMessageBox::Show("Disconnected: Packet Error.", true);
                break;
            case 3:
                MirMessageBox::Show("Disconnected: Server Crashed.", true);
                break;
            case 4:
                MirMessageBox::Show("Disconnected: Kicked by Admin.", true);
                break;
            case 5:
                MirMessageBox::Show("Disconnected: Maximum connections reached.", true);
                break;
        }

        GameScene::LogTime = 0;
    }

    void MirScene::Dispose(bool disposing)
    {

        MirControl::Dispose(disposing);

        if (!disposing)
        {
            return;
        }

        if (ActiveScene == this)
        {
            ActiveScene = nullptr;
        }

        _buttons = 0;
        _lastClickTime = 0;
        _clickedControl = nullptr;
    }
}
